package yagwl.client.widget;

import java.util.ArrayList;
import java.util.List;

import yagwl.client.widget.internal.ButtonBar;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.VerticalPanel;

/**
 * Lays out field groups and a button bar. Uses method chaining
 */
public class FormPanel extends Composite {
  private VerticalPanel contentVP = new VerticalPanel();
  private List<FormFieldGroup> groupList = new ArrayList<FormFieldGroup>();
  private String labelColumnWidth;
  private String dataColumnWidth;
  private String columnSpacing = "20px";
  private ButtonBar buttonBar = new ButtonBar();
  private SaveButtonClickCallback saveButtonClickCallback;


  public FormPanel() {
    contentVP.setWidth("100%");
    initWidget(contentVP);
  }

  /**
   * Renders the widget. This must be called for the widget to be rendered. Must
   * be called after field groups and action bar have been added.
   */
  public void renderUI() {
    buttonBar.renderUI();
    for (int i = 0; i < groupList.size(); i++) {
      FormFieldGroup group = groupList.get(i);
      // add buttonBar in the last group
      if (i == groupList.size() - 1)
        group.setButtonBar(buttonBar);
      if (group.getLabelColumnWidth() == null)
        group.setLabelColumnWidth(labelColumnWidth);
      if (group.getDataColumnWidth() == null)
        group.setDataColumnWidth(dataColumnWidth);
      group.setColumnSpacing(columnSpacing);
      group.renderUI();
      contentVP.add(group);
    }
  }

  /**
   * Add a field group
   */
  public void addFieldGroup(FormFieldGroup formGroup) {
    groupList.add(formGroup);
  }

  /**
   * Sets default label width for field groups
   */
  public FormPanel setLabelColumnWidth(String width) {
    this.labelColumnWidth = width;
    return this;
  }

  /**
   * Sets default data widget width for field groups
   */
  public FormPanel setDataColumnWidth(String width) {
    this.dataColumnWidth = width;
    return this;
  }

  /**
   * Sets column spacing for field groups
   */
  public FormPanel setColumnSpacing(String spacing) {
    this.columnSpacing = spacing;
    return this;
  }
  
  /**
   * Adds button
   */
  public void addButton(String label, ClickHandler clickHandler) {
    Button button = new Button(label);
    button.addClickHandler(clickHandler);
    buttonBar.add(button);
  }

  /**
   * Adds save button; inputs will be validated by the component
   */
  public void addSaveButton(String label,
      SaveButtonClickCallback saveButtonClickCallback) {
    Button button = new Button(label);
    this.saveButtonClickCallback = saveButtonClickCallback;
    button.addClickHandler(new SaveButtonClickHandler());
    buttonBar.add(button);
  }

  /**
   * Adds Cancel button which takes back to previous history state
   */
  public void addBackButton(String label) {
    addButton(label, new ClickHandler() {

      @Override
      public void onClick(ClickEvent event) {
        History.back();
      }
    });
  }

  /**
   * Adds Hide button which hides the form
   */
  public void addHideButton(String label) {
    addButton(label, new ClickHandler() {

      @Override
      public void onClick(ClickEvent event) {
        setVisible(false);
      }
    });
  }

  /**
   * Adds Close button to close the dialog box (useful only in a DialogBox)
   */
  public void addCloseDialogBoxButton(String label, final DialogBox dialogBox) {
    addButton(label, new ClickHandler() {

      @Override
      public void onClick(ClickEvent event) {
        dialogBox.hide();
      }
    });
  }

  public interface SaveButtonClickCallback {
    public void save();
  }

  private class SaveButtonClickHandler implements ClickHandler {

    @Override
    public void onClick(ClickEvent event) {
      String errorMessage = getValidationErrorMessage();
      if (errorMessage == null) {
        setBusy(true);
        saveButtonClickCallback.save();
        return;
      }
      setErrorMessage(errorMessage);
    }
  }

  /**
   * Displays or un-displays busy indicator
   */
  public void setBusy(boolean busy) {
    buttonBar.setBusy(busy);
  }

  /**
   * Displays message for 4 seconds
   * 
   * @param message
   *          message to be displayed
   */
  public void setMessage(String message) {
    buttonBar.setMessage(message, 4);
  }

  /**
   * Displays message
   * 
   * @param message
   *          message to be displayed
   * @param displaySeconds
   *          seconds for how long message is displayed
   */
  public void setMessage(String message, int displaySeconds) {
    buttonBar.setMessage(message, displaySeconds);
  }

  /**
   * Displays error message for 8 seconds
   * 
   * @param message
   *          error message to be displayed
   */
  public void setErrorMessage(String message) {
    buttonBar.setErrorMessage(message, 8);
  }

  /**
   * Displays error message
   * 
   * @param message
   *          error message to be displayed
   * @param displaySeconds
   *          seconds for how long error message is displayed
   */
  public void setErrorMessage(String message, int displaySeconds) {
    buttonBar.setErrorMessage(message, displaySeconds);
  }

  private String getValidationErrorMessage() {
    for (FormFieldGroup group : groupList) {
      for (FormField formField : group.getFieldList()) {
        if (formField.getDataWidget().getClass().equals(InputTextBox.class)) {
          InputTextBox input = (InputTextBox) formField.getDataWidget();
          if (formField.isRequired() && input.getText() == null)
            return "Error: " + formField.getLabel()
                + " - Required field missing";
          if (!input.isValid())
            return "Error: " + formField.getLabel() + " - Invalid format";
        }
        if (formField.getDataWidget() instanceof InputTextArea) {
          InputTextArea input = (InputTextArea) formField.getDataWidget();
          if (formField.isRequired() && input.getText() == null)
            return "Error: " + formField.getLabel()
                + " - Required field missing";
        }
      }
    }
    return null;
  }

}
